All files / src/components/user VODCard.tsx

0% Statements 0/12
0% Branches 0/10
0% Functions 0/2
0% Lines 0/12

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132                                                                                                                                                                                                                                                                       
'use client';
 
import React from 'react';
import Link from 'next/link';
import { Play, Film } from 'lucide-react';
import { cn } from '@/lib/utils';
import { FavoriteButton } from '@/components/user/FavoriteButton';
import { MOVIES_BACKDROPS } from '@/constants/backdrops';
 
interface VODCardProps {
  id: number;
  title: string;
  description?: string;
  year?: number | string;
  poster_url?: string;
  image_url?: string;
  backdrop_url?: string;
  rating?: number;
  progress?: number;
  category?: string;
  className?: string;
}
 
/**
 * VODCard - Modern card component for VOD content (Movies, Series, Kids, Anime, Novelas)
 *
 * Features:
 * - Modern design matching /user/content style
 * - Category badge at top
 * - Title and description overlay
 * - Bottom bar with year and Watch button
 * - Hover effects with elevation and border glow
 */
export default function VODCard({
  id,
  title,
  description: _description,
  year,
  poster_url,
  image_url,
  backdrop_url,
  rating,
  progress: _progress = 0,
  category,
  className}: VODCardProps) {
  // Use poster_url first, then image_url, then backdrop_url as fallback
  const displayImage = poster_url || image_url || backdrop_url;
 
  // Random placeholder images for cards without posters
  const placeholderImages = MOVIES_BACKDROPS;
 
  // Get a consistent random placeholder based on the ID
  const placeholderIndex = id % placeholderImages.length;
  const fallbackImage = placeholderImages[placeholderIndex];
 
  return (
    <Link
      href={`/user/content/${id}/watch`}
      className={cn(
        'group relative overflow-hidden rounded-xl bg-black/40 transition-all duration-500 hover:z-10 hover:scale-105 hover:shadow-[0_10px_40px_-10px_rgba(0,0,0,0.8)]',
        className
      )}
    >
      {/* Poster Image with Gradient Overlay - Fixed aspect ratio */}
      <div
        className="relative aspect-[2/3] bg-cover bg-center"
        style={{
          backgroundImage: displayImage
            ? `url(${displayImage})`
            : `url(${fallbackImage})`
        }}
      >
        {/* Blur overlay for placeholder images */}
        {!displayImage && (
          <div className="absolute inset-0 backdrop-blur-xl bg-slate-900/60 flex items-center justify-center">
            <Film className="h-16 w-16 text-slate-400" />
          </div>
        )}
 
        {/* Hover Overlay - Darkens and adds play button */}
        <div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-500 flex items-center justify-center backdrop-blur-[2px]">
          <div className="h-14 w-14 rounded-full bg-white/20 backdrop-blur-md flex items-center justify-center border border-white/30 shadow-[0_0_20px_rgba(255,255,255,0.2)] transform scale-0 group-hover:scale-100 transition-transform duration-300 delay-100">
            <Play className="h-6 w-6 text-white fill-white ml-1" />
          </div>
        </div>
 
        <div className="absolute inset-0 flex flex-col justify-between bg-gradient-to-t from-black via-black/20 to-transparent p-4 opacity-100 group-hover:opacity-0 transition-opacity duration-300">
          {/* Category Badge and Favorite Button */}
          <div className="flex items-center justify-between gap-2 text-xs text-slate-300">
            {category && (
              <span className="rounded-md bg-black/60 backdrop-blur-md px-2 py-0.5 uppercase tracking-wider text-[10px] font-bold border border-white/10 shadow-sm">
                {category}
              </span>
            )}
            {/* Favorite button kept visible but subtle */}
            {/* <div onClick={(e) => e.preventDefault()}>
              <FavoriteButton
                contentType="movie"
                contentId={String(id)}
                className="h-8 w-8"
                iconClassName="h-4 w-4"
              />
            </div> */}
          </div>
        </div>
      </div>
 
      {/* Bottom Info - Only visible on hover in some designs, but here we keep it clean */}
      <div className="absolute bottom-0 left-0 w-full p-4 bg-gradient-to-t from-black to-transparent pt-10 transform translate-y-2 group-hover:translate-y-0 transition-transform duration-500">
        <div className="flex items-center justify-between mb-1">
          <h3 className="text-sm font-bold text-white line-clamp-1 text-shadow-sm">
            {title}
          </h3>
          <div onClick={(e) => e.preventDefault()} className="opacity-0 group-hover:opacity-100 transition-opacity duration-300">
            <FavoriteButton
              contentType="movie"
              contentId={String(id)}
              className="h-6 w-6 hover:bg-white/10 rounded-full p-1"
              iconClassName="h-3 w-3"
            />
          </div>
        </div>
 
        <div className="flex items-center gap-2 text-[10px] text-gray-300 font-medium">
          {year && <span className="bg-white/10 px-1.5 rounded text-white">{year}</span>}
          {rating && <span className="text-green-400">{rating} Match</span>}
        </div>
      </div>
    </Link>
  );
}